﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Diagnostics;


namespace a14_MTA_calcPrime_ByAsyncOnDelegate
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool goOn = false;
        private long curPrime = 3;

        private Stopwatch stopWatch;

        private int uiThreadId;


        private delegate void CalcPrimeDelegate(out long prime, out long elapsed);


        public MainWindow()
        {
            InitializeComponent();

            stopWatch = new Stopwatch();
        }

        private void StartOrStopCalc(object sender, RoutedEventArgs e)
        {
            //uiThreadId = Thread.CurrentThread.ManagedThreadId;

            if (goOn)
            {
                goOn = false;
                startOrStopBtn.Content = "Resume";
                Debug.WriteLine("Click to stop calc prime, threadId=" + Thread.CurrentThread.ManagedThreadId);
            }
            else
            {
                goOn = true;
                startOrStopBtn.Content = "Stop";

                Debug.WriteLine("Click to start calc prime, threadId=" + Thread.CurrentThread.ManagedThreadId);

                StartCalcAsync();
            }
        }

        private void StartCalcAsync()
        {
            CalcPrimeDelegate calcDelegate = new CalcPrimeDelegate(CheckNextPrime);
            AsyncCallback completeCallBack = new AsyncCallback(ProcessPrime);

            long prime = 0;
            long elapsed = 0;
            // async on delegate,  在threadpool中分配一个thread异步执行该delegate, 执行完毕后后会回调callBack.
            IAsyncResult result = calcDelegate.BeginInvoke(out prime, out elapsed, completeCallBack, null);
        }

        //特别注意, AsyncCallback是运行在worker thread中的. 
        //故这里的工作实际放在CheckNextPrime结束时也行, 此例使用AsyncCallback仅是演示结果不许在uiThread中时的情形
        private void ProcessPrime(IAsyncResult result)
        {
            Debug.WriteLine("ProcessPrime, threadId=" + Thread.CurrentThread.ManagedThreadId);

            //AsyncResult是delegate的AsyncCallback的入口参数IAsyncResult实现类.
            System.Runtime.Remoting.Messaging.AsyncResult ar = (System.Runtime.Remoting.Messaging.AsyncResult)result;
            CalcPrimeDelegate caller = (CalcPrimeDelegate)ar.AsyncDelegate;

            long prime = 0;
            long elapsed = 0;
            caller.EndInvoke(out prime, out elapsed, result);

            startOrStopBtn.Dispatcher.BeginInvoke(new Action<long, long>(UpdatePrimeUi), prime, elapsed);

        }

        private void UpdatePrimeUi(long bigPrimeNum, long elapsedMSec)
        {
            Debug.WriteLine("Update UI, threadId=" + Thread.CurrentThread.ManagedThreadId);

            if (bigPrimeNum > 0)
            {
                bigPrime.Text = "Bigges prime: " + bigPrimeNum;
                elapsedTime.Text = "Elapsed time: " + elapsedMSec;
            }

            if (goOn)
            {
                Debug.WriteLine("Trig next calc");
                StartCalcAsync();
            }
        }


        private void CheckNextPrime(out long prime, out long elapsed)
        {
            Debug.WriteLine("Calc next prime, curPrime=" + curPrime + ", threadId=" + Thread.CurrentThread.ManagedThreadId);

            stopWatch.Start();

            prime = 0;
            elapsed = 0;

            bool notPrime = false;

            for (long i = 3; i <= Math.Sqrt(curPrime); i++)
            {
                if (curPrime % i == 0)
                {
                    // Set not a prime flag to true.
                    notPrime = true;
                    break;
                }
            }

            // If a prime number.
            if (!notPrime)
            {
                stopWatch.Stop();
                prime = curPrime;
                elapsed = stopWatch.ElapsedMilliseconds;
            }

            curPrime += 2;
        }

    }
}
